﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Meow.Core.Input;

public class KeyState
{
    public bool IsPressed;
    public float PressedElapsedTime;
    public List<Action> KeyDownActions = new List<Action>();
    public List<Action> KeyUpActions = new List<Action>();
    //public float LastKeyUpElapsedTime;
}

public static class InputHandler
{
    static readonly Keys[] _keysCanHandle ={
                    Keys.D1,
                    Keys.D2,
                    Keys.D3,
                    Keys.D4,
                    Keys.D5,
                    Keys.D6,
                    Keys.D7,
                    Keys.D8,
                    Keys.D9,
                    Keys.D0,
                    Keys.A,
                    Keys.B,
                    Keys.C,
                    Keys.D,
                    Keys.E,
                    Keys.F,
                    Keys.G,
                    Keys.H,
                    Keys.I,
                    Keys.J,
                    Keys.K,
                    Keys.L,
                    Keys.M,
                    Keys.N,
                    Keys.O,
                    Keys.P,
                    Keys.Q,
                    Keys.R,
                    Keys.S,
                    Keys.T,
                    Keys.U,
                    Keys.V,
                    Keys.W,
                    Keys.X,
                    Keys.Y,
                    Keys.Z,
                    Keys.Back,
                    Keys.Tab,
                    Keys.Enter,
                    Keys.CapsLock,
                    Keys.Escape,
                    Keys.Space,
                    Keys.PageUp,
                    Keys.PageDown,
                    Keys.End,
                    Keys.Home,
                    Keys.Left,
                    Keys.Up,
                    Keys.Right,
                    Keys.Down,
                    Keys.Select,
                    Keys.Print,
                    Keys.Execute,
                    Keys.PrintScreen,
                    Keys.Insert,
                    Keys.Delete,
                    Keys.Help,
    };

    public static readonly HashSet<Keys> AllKeysCanHandle = _keysCanHandle.ToHashSet();


    public static readonly Dictionary<Keys, KeyState> AllKeysHandling = new Dictionary<Keys, KeyState>();

    public static GameWindow Window => Application.Engine.Window;
    public static int WindowWidth => Application.GraphicsDevice.PresentationParameters.BackBufferWidth;
    public static int WindowHeight => Application.GraphicsDevice.PresentationParameters.BackBufferHeight;


    private static MouseState _oldMouse;
    private static MouseState _newMouse;
    public static MouseState OldMouse => _oldMouse;
    public static MouseState NewMouse => _newMouse;

    public static bool LockTheMouse;

    internal static void Initialize()
    {
        _newMouse = Mouse.GetState();
    }

    /// <summary>
    /// Add a Key to handle
    /// </summary>
    /// <returns>If the key can be handled - true ; otherwise - false</returns>
    public static bool AddKeyToHandle(Keys key)
    {
        if (AllKeysCanHandle.Contains(key))
        {
            AllKeysHandling.TryAdd(key, new KeyState());
            return true;
        }

        return false;
    }

    internal static void AfterUpdate(GameTime gameTime)
    {
        if (LockTheMouse)
        {
            Mouse.SetPosition(WindowWidth / 2, WindowHeight / 2);
            _oldMouse = Mouse.GetState();
            _newMouse = _oldMouse;
        }
    }

    internal static void Update(GameTime gameTime)
    {
        _oldMouse = _newMouse;
        _newMouse = Mouse.GetState();

        foreach (var (key, state) in AllKeysHandling)
        {
            if (Keyboard.GetState().IsKeyDown(key))
            {
                // key has not pressed
                if (!state.IsPressed)
                {
                    // key down events
                    foreach (var action in state.KeyDownActions)
                        action.Invoke();

                    state.IsPressed = true;
                    state.PressedElapsedTime = 0;
                }
                else
                {
                    // key has pressed from last update
                    state.IsPressed = true;
                    state.PressedElapsedTime += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
                }
            }
            else
            {
                if (state.IsPressed)
                {
                    // key up events
                    foreach (var action in state.KeyUpActions)
                        action.Invoke();
                }

                state.IsPressed = false;
                state.PressedElapsedTime = 0;
            }

        }
    }
}
